﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using ZGRemote.Common.Extensions;
using ZGRemote.Common.Message;
using ZGRemote.Common.Networking;

namespace ZGRemote.Common.Processor
{
    public abstract class HandlerBaseBase
    {
        private static ConcurrentDictionary<Guid, MessageWaitBase> messageWaitEventTable
            = new ConcurrentDictionary<Guid, MessageWaitBase>();

        public static void ProcessingMessage(UserContext user, MessageBase message)
        {
            if (MessageProcessor.Message2HandlerTable.TryGetValue(message.GetType(), out Excute excute))
            {
                excute.Invoke(user, message);
            }
            else if(messageWaitEventTable.TryRemove(message.ID, out MessageWaitBase messageWait))
            {
                messageWait.Message = message;
            }


        }

        protected static T SendMessage<T>(UserContext user, MessageBase message) where T : MessageBase
        {
            if (user?.IsConnect != true) throw new Exception("The client has been disconnected!");
            using (MessageWaitBase messageWait = new MessageWaitEvent())
            {
                Guid guid = Guid.NewGuid();
                message.ID = guid;
                messageWaitEventTable.TryAdd(guid, messageWait);
                user.SendPack(MessageProcessor.Pack(message));

                T result = messageWait.WaitMessage() as T;
                messageWaitEventTable.TryRemove(guid, out _);
                if (result == null) throw new SocketException(10060); // request timeout
                return result;
            }
        }

        protected async static Task<T> SendMessageAsync<T>(UserContext user, MessageBase message) where T : MessageBase
        {
            if (user?.IsConnect != true) throw new SocketException(10057); // socket disconnect
            using (MessageWaitBase messageWait = new MessageWaitAsync())
            {
                Guid guid = Guid.NewGuid();
                message.ID = guid;
                messageWaitEventTable.TryAdd(guid, messageWait);
                user.SendPack(MessageProcessor.Pack(message));

                T result = await messageWait.WaitMessageAsync() as T;
                messageWaitEventTable.TryRemove(guid, out _);
                if (result == null) throw new SocketException(10060); // request timeout
                return result;
            }
        }

        protected static void SendMessage(UserContext user, MessageBase message)
        {
            if (user?.IsConnect != true) throw new SocketException(10057); // socket disconnect
            user.SendPack(MessageProcessor.Pack(message));
        }
    }
}
